﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;

namespace TypeFundamentals
{
    public class BuiltinTypes
    {
        public static void BuildInTypesInfo()
        {
            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(bool), bool.TrueString, bool.FalseString);
            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(char), Char.MaxValue, Char.MinValue);

            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(SByte), SByte.MaxValue, SByte.MinValue);
            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(Int16), Int16.MaxValue, Int16.MinValue);
            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(Int32), Int32.MaxValue, Int32.MinValue);
            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(Int64), Int64.MaxValue, Int64.MinValue);

            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(Byte), Byte.MaxValue, Byte.MinValue);
            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(UInt16), UInt16.MaxValue, UInt16.MinValue);
            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(UInt32), UInt32.MaxValue, UInt32.MinValue);
            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(UInt64), UInt64.MaxValue, UInt64.MinValue);

            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(Decimal), Decimal.MaxValue, Decimal.MinValue);

            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(float), float.MaxValue, float.MinValue);
            Console.WriteLine("Sizeof: {0} Max: {1,20}, Min: {2,20}", sizeof(double), double.MaxValue, double.MinValue);

            //'System.DateTime' does not have a predefined size, 
            //therefore sizeof can only be used in an unsafe context 
            //(consider using System.Runtime.InteropServices.Marshal.SizeOf)
            //sizeof(DateTime);
           

            //error CS0208: Cannot take the address of, get the size of, 
            // or declare a pointer to a managed type ('SizeOf.Program.MyStructWithReference')
            //sizeof(MyStructWithReference);


            //Unhandled Exception: System.ArgumentException: Type 'System.DateTime' cannot be
            //marshaled as an unmanaged structure; no meaningful size or offset can be computed.
            //Marshal.SizeOf(new DateTime()) or Marshal.SizeOf(new WithCharInMarshalAs()) with [StructLayout( LayoutKind.Auto)]
            //

            //Cannot take the address of, get the size of, or declare a pointer to a managed type
            //('TypeFundamentals.BuiltinTypes.MyStruct<int>')
            //var i = sizeof(MyStruct<int>);

            // 1
            Console.WriteLine("Marshal size of emtpy struct: {0} ",Marshal.SizeOf(new EmptyStruct()));
            // 16
            Console.WriteLine("Marshal size of struct with reference field: {0} ", Marshal.SizeOf(new MyStructWithReference()));
            // 1
            Console.WriteLine("Marshal size of struct with char: {0} ", Marshal.SizeOf(new StrustWithChar()));
            // 4
            Console.WriteLine("Marshal size of struct WithCharInMarshalAs: {0} ", Marshal.SizeOf(new WithCharInMarshalAs()));
        }
        struct EmptyStruct
        {
            
        }

        struct MyStructWithReference
        {
            // marshal as char*, is 4 on 32bits, 8 on 64 bits
            string s;
            object o;
        }

        struct StrustWithChar
        {
            // marshal as ansi default
            char c1;
        }

        [StructLayout( LayoutKind.Sequential)]
        struct WithCharInMarshalAs
        {
            char c1;
            [MarshalAs(UnmanagedType.I2)]
            char c2;
            
        }

        struct MyStruct<T>
        {
            T t;
        }
    }
}
